using Domain.Weather;
using Infratructure.Interface;
using MediatR;
using MES.Server.API.Application.Command.Weather;
using MES.Server.API.Dto.Weather;
using Microsoft.Extensions.Logging;
using ReturnValue;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Yitter.IdGenerator;

namespace MES.Server.API.Application.Handler.Weather
{
    /// <summary>
    /// 处理获取模拟天气信息的处理器类
    /// </summary>
    public class GetMockWeatherHandler : IRequestHandler<GetMockWeatherCommand, ApiResult<WeatherOutPut>>
    {
        private readonly IRepository<WeatherModel> _weatherRepository;
        private readonly ILogger<GetMockWeatherHandler> _logger;
        private readonly Random _random;

        // 天气状况选项
        private readonly string[] _weatherConditions = { "晴", "多云", "阴", "小雨", "中雨", "大雨", "雷阵雨", "雪", "雾", "霾" };
        private readonly string[] _windDirections = { "北风", "东北风", "东风", "东南风", "南风", "西南风", "西风", "西北风" };
        private readonly string[] _weatherIcons = { "100", "101", "102", "103", "104", "300", "301", "302", "303", "304", "305", "306", "307", "308", "309", "310", "311", "312", "313", "314", "315", "316", "317", "318", "399", "400", "401", "402", "403", "404", "405", "406", "407", "408", "409", "410", "499", "500", "501", "502", "503", "504", "507", "508", "509", "510", "511", "512", "513", "514", "515", "900", "901", "999" };

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="weatherRepository">天气数据仓储</param>
        /// <param name="logger">日志记录器</param>
        public GetMockWeatherHandler(
            IRepository<WeatherModel> weatherRepository,
            ILogger<GetMockWeatherHandler> logger)
        {
            _weatherRepository = weatherRepository;
            _logger = logger;
            _random = new Random();
        }

        /// <summary>
        /// 处理获取模拟天气信息的请求
        /// </summary>
        /// <param name="request">请求命令</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>包含模拟天气信息的API结果</returns>
        public async Task<ApiResult<WeatherOutPut>> Handle(GetMockWeatherCommand request, CancellationToken cancellationToken)
        {
            var result = new ApiResult<WeatherOutPut>();

            try
            {
                // 1. 检查输入参数
                if (string.IsNullOrWhiteSpace(request.CityName))
                {
                    result.Code = ReturnValue.StatusCode.Fail;
                    result.Message = "城市名称不能为空";
                    return result;
                }

                // 2. 检查数据库中是否有该城市的模拟天气数据
                var existingWeather = _weatherRepository.GetAll()
                    .Where(w => w.CityName == request.CityName && !w.IsDel && w.DataSource == "模拟数据")
                    .OrderByDescending(w => w.UpdateTime)
                    .FirstOrDefault();

                // 3. 生成模拟天气数据
                var mockWeatherData = GenerateMockWeatherData(request.CityName, request.Days);

                // 4. 保存或更新模拟天气数据到数据库
                if (existingWeather == null)
                {
                    // 创建新记录
                    var weather = new WeatherModel
                    {
                        Id = YitIdHelper.NextId(),
                        CityName = request.CityName,
                        CityId = GenerateCityId(request.CityName),
                        Longitude = GenerateRandomCoordinate(110, 120), // 中国经度范围
                        Latitude = GenerateRandomCoordinate(20, 50),    // 中国纬度范围
                        DataSource = "模拟数据",
                        UpdateTime = DateTime.Now,
                        CreateTime = DateTime.Now,
                        IsDel = false,
                        CreaterPeople = "system"
                    };

                    // 设置第一天的天气数据作为当前天气
                    if (mockWeatherData.DailyForecast.Any())
                    {
                        var firstDay = mockWeatherData.DailyForecast.First();
                        weather.Temperature = firstDay.MaxTemperature;
                        weather.MaxTemperature = firstDay.MaxTemperature;
                        weather.MinTemperature = firstDay.MinTemperature;
                        weather.WeatherCondition = firstDay.DayWeather;
                        weather.WeatherIcon = firstDay.DayIcon;
                        weather.WindDirection = firstDay.WindDirection;
                        weather.WindSpeed = firstDay.WindSpeed;
                        weather.Humidity = firstDay.Humidity;
                        weather.Pressure = firstDay.Pressure;
                        weather.Visibility = firstDay.Visibility;
                        weather.UvIndex = firstDay.UvIndex;
                        weather.FeelsLike = firstDay.MaxTemperature - 2; // 体感温度比实际温度低2度
                        weather.CloudCover = firstDay.CloudCover;
                        weather.DewPoint = firstDay.DewPoint;
                        weather.WeatherUpdateTime = DateTime.Now;
                    }

                    await _weatherRepository.AddAsync(weather);
                }
                else
                {
                    // 更新现有记录
                    existingWeather.UpdateTime = DateTime.Now;
                    existingWeather.CreaterPeople = "system";

                    // 更新第一天的天气数据作为当前天气
                    if (mockWeatherData.DailyForecast.Any())
                    {
                        var firstDay = mockWeatherData.DailyForecast.First();
                        existingWeather.Temperature = firstDay.MaxTemperature;
                        existingWeather.MaxTemperature = firstDay.MaxTemperature;
                        existingWeather.MinTemperature = firstDay.MinTemperature;
                        existingWeather.WeatherCondition = firstDay.DayWeather;
                        existingWeather.WeatherIcon = firstDay.DayIcon;
                        existingWeather.WindDirection = firstDay.WindDirection;
                        existingWeather.WindSpeed = firstDay.WindSpeed;
                        existingWeather.Humidity = firstDay.Humidity;
                        existingWeather.Pressure = firstDay.Pressure;
                        existingWeather.Visibility = firstDay.Visibility;
                        existingWeather.UvIndex = firstDay.UvIndex;
                        existingWeather.FeelsLike = firstDay.MaxTemperature - 2;
                        existingWeather.CloudCover = firstDay.CloudCover;
                        existingWeather.DewPoint = firstDay.DewPoint;
                        existingWeather.WeatherUpdateTime = DateTime.Now;
                    }

                    await _weatherRepository.UpdateAsync(existingWeather);
                }

                result.Code = ReturnValue.StatusCode.Success;
                result.Message = $"成功生成 {request.CityName} 的模拟天气数据";
                result.Data = mockWeatherData;
                return result;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "生成城市 {CityName} 的模拟天气数据时发生错误", request.CityName);
                result.Code = ReturnValue.StatusCode.Fail;
                result.Message = $"生成模拟天气数据失败: {ex.Message}";
                return result;
            }
        }

        /// <summary>
        /// 生成模拟天气数据
        /// </summary>
        /// <param name="cityName">城市名称</param>
        /// <param name="days">预报天数</param>
        /// <returns>模拟天气输出对象</returns>
        private WeatherOutPut GenerateMockWeatherData(string cityName, int days)
        {
            var output = new WeatherOutPut
            {
                CityName = cityName,
                CityId = GenerateCityId(cityName),
                Longitude = GenerateRandomCoordinate(110, 120),
                Latitude = GenerateRandomCoordinate(20, 50),
                UpdateTime = DateTime.Now,
                DataSource = "模拟数据"
            };

            // 生成指定天数的天气预报
            for (int i = 0; i < days; i++)
            {
                var date = DateTime.Now.AddDays(i);
                var dailyWeather = GenerateDailyWeather(date, i);
                output.DailyForecast.Add(dailyWeather);
            }

            return output;
        }

        /// <summary>
        /// 生成单日天气数据
        /// </summary>
        /// <param name="date">日期</param>
        /// <param name="dayOffset">天数偏移</param>
        /// <returns>单日天气数据</returns>
        private DailyWeather GenerateDailyWeather(DateTime date, int dayOffset)
        {
            // 根据季节调整温度范围
            var season = GetSeason(date);
            var (minTemp, maxTemp) = GetTemperatureRange(season, dayOffset);

            // 生成天气状况
            var weatherCondition = GetRandomWeatherCondition(season);
            var weatherIcon = GetWeatherIcon(weatherCondition);

            // 生成风向和风速
            var windDirection = _windDirections[_random.Next(_windDirections.Length)];
            var windSpeed = _random.Next(5, 25); // 5-25 km/h

            // 生成湿度（根据天气状况调整）
            var humidity = GetHumidityByWeather(weatherCondition);

            // 生成气压
            var pressure = _random.Next(980, 1030); // 980-1030 百帕

            // 生成能见度
            var visibility = GetVisibilityByWeather(weatherCondition);

            // 生成紫外线指数
            var uvIndex = GetUvIndexBySeason(season, weatherCondition);

            // 生成云量
            var cloudCover = GetCloudCoverByWeather(weatherCondition);

            // 生成露点温度
            var dewPoint = maxTemp - _random.Next(5, 15);

            // 生成降水量
            var precipitation = GetPrecipitationByWeather(weatherCondition);

            // 生成降水概率
            var precipitationProbability = GetPrecipitationProbability(weatherCondition);

            return new DailyWeather
            {
                Date = date,
                MaxTemperature = maxTemp,
                MinTemperature = minTemp,
                DayWeather = weatherCondition,
                NightWeather = GetNightWeather(weatherCondition),
                DayIcon = weatherIcon,
                NightIcon = GetNightWeatherIcon(weatherCondition),
                WindDirection = windDirection,
                WindSpeed = windSpeed,
                Humidity = humidity,
                Pressure = pressure,
                Visibility = visibility,
                UvIndex = uvIndex,
                Precipitation = precipitation,
                PrecipitationProbability = precipitationProbability,
                CloudCover = cloudCover,
                DewPoint = dewPoint
            };
        }

        /// <summary>
        /// 获取季节
        /// </summary>
        /// <param name="date">日期</param>
        /// <returns>季节</returns>
        private Season GetSeason(DateTime date)
        {
            var month = date.Month;
            if (month >= 3 && month <= 5) return Season.Spring;
            if (month >= 6 && month <= 8) return Season.Summer;
            if (month >= 9 && month <= 11) return Season.Autumn;
            return Season.Winter;
        }

        /// <summary>
        /// 获取温度范围
        /// </summary>
        /// <param name="season">季节</param>
        /// <param name="dayOffset">天数偏移</param>
        /// <returns>温度范围</returns>
        private (double min, double max) GetTemperatureRange(Season season, int dayOffset)
        {
            // 添加一些随机变化
            var randomVariation = _random.Next(-3, 4);
            
            return season switch
            {
                Season.Spring => (5 + randomVariation + dayOffset, 20 + randomVariation + dayOffset),
                Season.Summer => (20 + randomVariation + dayOffset, 35 + randomVariation + dayOffset),
                Season.Autumn => (10 + randomVariation + dayOffset, 25 + randomVariation + dayOffset),
                Season.Winter => (-10 + randomVariation + dayOffset, 10 + randomVariation + dayOffset),
                _ => (10, 20)
            };
        }

        /// <summary>
        /// 获取随机天气状况
        /// </summary>
        /// <param name="season">季节</param>
        /// <returns>天气状况</returns>
        private string GetRandomWeatherCondition(Season season)
        {
            // 根据季节调整天气状况的概率
            var conditions = season switch
            {
                Season.Spring => new[] { "晴", "多云", "阴", "小雨", "中雨" },
                Season.Summer => new[] { "晴", "多云", "雷阵雨", "小雨", "中雨", "大雨" },
                Season.Autumn => new[] { "晴", "多云", "阴", "小雨", "雾" },
                Season.Winter => new[] { "晴", "多云", "阴", "雪", "雾", "霾" },
                _ => _weatherConditions
            };

            return conditions[_random.Next(conditions.Length)];
        }

        /// <summary>
        /// 获取天气图标
        /// </summary>
        /// <param name="weatherCondition">天气状况</param>
        /// <returns>天气图标代码</returns>
        private string GetWeatherIcon(string weatherCondition)
        {
            return weatherCondition switch
            {
                "晴" => "100",
                "多云" => "101",
                "阴" => "104",
                "小雨" => "300",
                "中雨" => "301",
                "大雨" => "302",
                "雷阵雨" => "304",
                "雪" => "400",
                "雾" => "501",
                "霾" => "502",
                _ => "100"
            };
        }

        /// <summary>
        /// 获取夜间天气状况
        /// </summary>
        /// <param name="dayWeather">白天天气状况</param>
        /// <returns>夜间天气状况</returns>
        private string GetNightWeather(string dayWeather)
        {
            return dayWeather switch
            {
                "晴" => "晴",
                "多云" => "多云",
                "阴" => "阴",
                "小雨" => "小雨",
                "中雨" => "小雨",
                "大雨" => "中雨",
                "雷阵雨" => "小雨",
                "雪" => "雪",
                "雾" => "雾",
                "霾" => "霾",
                _ => dayWeather
            };
        }

        /// <summary>
        /// 获取夜间天气图标
        /// </summary>
        /// <param name="weatherCondition">天气状况</param>
        /// <returns>夜间天气图标代码</returns>
        private string GetNightWeatherIcon(string weatherCondition)
        {
            return weatherCondition switch
            {
                "晴" => "150",
                "多云" => "151",
                "阴" => "154",
                "小雨" => "350",
                "中雨" => "351",
                "大雨" => "352",
                "雷阵雨" => "354",
                "雪" => "450",
                "雾" => "551",
                "霾" => "552",
                _ => "150"
            };
        }

        /// <summary>
        /// 根据天气状况获取湿度
        /// </summary>
        /// <param name="weatherCondition">天气状况</param>
        /// <returns>湿度百分比</returns>
        private int GetHumidityByWeather(string weatherCondition)
        {
            return weatherCondition switch
            {
                "晴" => _random.Next(30, 60),
                "多云" => _random.Next(40, 70),
                "阴" => _random.Next(60, 80),
                "小雨" => _random.Next(70, 90),
                "中雨" => _random.Next(80, 95),
                "大雨" => _random.Next(85, 98),
                "雷阵雨" => _random.Next(75, 90),
                "雪" => _random.Next(60, 80),
                "雾" => _random.Next(90, 100),
                "霾" => _random.Next(70, 85),
                _ => _random.Next(40, 70)
            };
        }

        /// <summary>
        /// 根据天气状况获取能见度
        /// </summary>
        /// <param name="weatherCondition">天气状况</param>
        /// <returns>能见度（公里）</returns>
        private double GetVisibilityByWeather(string weatherCondition)
        {
            return weatherCondition switch
            {
                "晴" => _random.Next(15, 30),
                "多云" => _random.Next(10, 25),
                "阴" => _random.Next(8, 20),
                "小雨" => _random.Next(5, 15),
                "中雨" => _random.Next(3, 10),
                "大雨" => _random.Next(1, 8),
                "雷阵雨" => _random.Next(2, 12),
                "雪" => _random.Next(3, 15),
                "雾" => _random.Next(0, 5),
                "霾" => _random.Next(1, 8),
                _ => _random.Next(10, 20)
            };
        }

        /// <summary>
        /// 根据季节和天气状况获取紫外线指数
        /// </summary>
        /// <param name="season">季节</param>
        /// <param name="weatherCondition">天气状况</param>
        /// <returns>紫外线指数</returns>
        private int GetUvIndexBySeason(Season season, string weatherCondition)
        {
            if (weatherCondition.Contains("雨") || weatherCondition.Contains("雪") || weatherCondition.Contains("雾") || weatherCondition.Contains("霾"))
                return _random.Next(0, 3);

            return season switch
            {
                Season.Spring => _random.Next(3, 7),
                Season.Summer => _random.Next(6, 11),
                Season.Autumn => _random.Next(2, 6),
                Season.Winter => _random.Next(1, 4),
                _ => _random.Next(3, 6)
            };
        }

        /// <summary>
        /// 根据天气状况获取云量
        /// </summary>
        /// <param name="weatherCondition">天气状况</param>
        /// <returns>云量百分比</returns>
        private int GetCloudCoverByWeather(string weatherCondition)
        {
            return weatherCondition switch
            {
                "晴" => _random.Next(0, 20),
                "多云" => _random.Next(30, 70),
                "阴" => _random.Next(80, 100),
                "小雨" => _random.Next(70, 90),
                "中雨" => _random.Next(80, 95),
                "大雨" => _random.Next(85, 100),
                "雷阵雨" => _random.Next(70, 90),
                "雪" => _random.Next(60, 85),
                "雾" => _random.Next(90, 100),
                "霾" => _random.Next(70, 90),
                _ => _random.Next(30, 70)
            };
        }

        /// <summary>
        /// 根据天气状况获取降水量
        /// </summary>
        /// <param name="weatherCondition">天气状况</param>
        /// <returns>降水量（毫米）</returns>
        private double GetPrecipitationByWeather(string weatherCondition)
        {
            return weatherCondition switch
            {
                "晴" => 0,
                "多云" => 0,
                "阴" => 0,
                "小雨" => _random.Next(1, 10),
                "中雨" => _random.Next(10, 25),
                "大雨" => _random.Next(25, 50),
                "雷阵雨" => _random.Next(5, 20),
                "雪" => _random.Next(1, 15),
                "雾" => 0,
                "霾" => 0,
                _ => 0
            };
        }

        /// <summary>
        /// 根据天气状况获取降水概率
        /// </summary>
        /// <param name="weatherCondition">天气状况</param>
        /// <returns>降水概率百分比</returns>
        private int GetPrecipitationProbability(string weatherCondition)
        {
            return weatherCondition switch
            {
                "晴" => _random.Next(0, 10),
                "多云" => _random.Next(10, 30),
                "阴" => _random.Next(30, 50),
                "小雨" => _random.Next(60, 80),
                "中雨" => _random.Next(80, 95),
                "大雨" => _random.Next(90, 100),
                "雷阵雨" => _random.Next(70, 90),
                "雪" => _random.Next(50, 80),
                "雾" => _random.Next(20, 40),
                "霾" => _random.Next(10, 30),
                _ => _random.Next(20, 50)
            };
        }

        /// <summary>
        /// 生成城市ID
        /// </summary>
        /// <param name="cityName">城市名称</param>
        /// <returns>城市ID</returns>
        private string GenerateCityId(string cityName)
        {
            // 简单的城市ID生成逻辑
            var hash = cityName.GetHashCode();
            return Math.Abs(hash).ToString().PadLeft(9, '0');
        }

        /// <summary>
        /// 生成随机坐标
        /// </summary>
        /// <param name="min">最小值</param>
        /// <param name="max">最大值</param>
        /// <returns>随机坐标值</returns>
        private double GenerateRandomCoordinate(int min, int max)
        {
            return _random.Next(min * 100, max * 100) / 100.0;
        }

        /// <summary>
        /// 季节枚举
        /// </summary>
        private enum Season
        {
            Spring,
            Summer,
            Autumn,
            Winter
        }
    }
}
